//
//  Toast.m
//  YanXiuWang
//
//  Created by 招利 李 on 16/11/18.
//  Copyright © 2016年 小分队. All rights reserved.
//

#import "ToastManager.h"
#import <objc/runtime.h>
#define AppShared [UIApplication sharedApplication]
#define ScreenSize [UIScreen mainScreen].bounds.size

@interface ToastManager() {
    
@package
    ToastTask *_currentToast;
    ToastModal *_currentModal;
//    
//    NSTimeInterval _lastDismissTime;
//    dispatch_block_t _afterBlock;
    
    UIWindow *_overlayWindow;
}

+ (UIView *)createContainerView:(ToastTask *)task;
+ (UILabel *)createLabelMaxLines:(CGFloat)numberOfLines;

@end

@interface ToastManager (Animate)

@property (nonatomic, readonly) UIWindow *overlayWindow;

- (void)animateTasks:(BOOL)isAfter;

+ (void)registerViewControllerClass:(Class)cls;
+ (NSArray *)toastFilterWithController:(__kindof UIViewController *)controller;

@end

@interface ToastTask () {
@package
    BOOL _overlayDismissOnTapped;
    BOOL _overlay;
    BOOL _visable;
    __weak UIViewController * _parentController;
    UIViewController * _childController;
    UIView * _containerView;
    UIView * _view;
    dispatch_block_t _showAnimationsBlock;  // mast be use `__weak typeof(self) weakSelf = self`;
    dispatch_block_t _hideAnimationsBlock;  // mast be use `__weak typeof(self) weakSelf = self`;
    dispatch_block_t _onDismissBlock;       // mast be use `__weak typeof(self) weakSelf = self`;
    dispatch_block_t _animationsBlock;
    NSTimeInterval _duration;
    
    CGAffineTransform _defaultTransform;
    CGFloat _defaultCornerRadius;
    CGSize _defaultSize;

    CGFloat _cornerRadius;
    CGFloat _alpha;
    CGRect _frame;
    
    UIEdgeInsets _viewInsets;
    NSTimeInterval _dismissTime;
    UIViewAutoresizing _autoresizingMask;
}

@end

#pragma mark - Overlay 覆盖层 视图
@interface OverlayToastView : UIView
@end
@implementation OverlayToastView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if (Toast.currentModal != nil) return view;
    // 手势操作穿透到 主Window
    if (view == nil || [view isEqual:self]) {
        UIWindow *window = [UIApplication sharedApplication].keyWindow ?: [UIApplication sharedApplication].windows.firstObject;
        return [window hitTest:point withEvent:event] ?: view;
    }
    return view;
}

@end

#pragma mark - Overlay 覆盖层 控制器
@interface OverlayController : UIViewController <UIGestureRecognizerDelegate>
@end
@implementation OverlayController

- (void)loadView {
    self.view = [[OverlayToastView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.view.backgroundColor = [UIColor clearColor];
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    CGPoint point = [gestureRecognizer locationInView:self.view];
    for (UIView *view in self.view.subviews) {
        if (CGRectContainsPoint(view.frame, point)) {
            return NO;
        }
    }
    return YES;
}

@end

#pragma mark - viewDidDisappear 勾子
@implementation UIViewController (ToastDisappear)

- (void)registerToastController {
    // 为防止重复 勾 viewDidDisappear 用 dispatch_once 确保每个类只勾 1 次
    __block Class cls = [self class];
    dispatch_once_t onceToken = [objc_getAssociatedObject(cls, "toastRegisterOnceToken") longValue];
    dispatch_once(&onceToken, ^{
        [ToastManager registerViewControllerClass:cls];
    });
    objc_setAssociatedObject(cls, "toastRegisterOnceToken", @(onceToken), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)toastDidDisappearAndReCall:(BOOL)animated {
    // 回调原 Controller 的 viewDidDissappear
    [self _selfDidDisappear:animated];
    [self toastDidDisappear:animated];
}

- (void)toastDidDisappear:(BOOL)animated {
    for (ToastTask *task in [ToastManager toastFilterWithController:self]) {
        [task dismissLater];
    }
    [[ToastManager shared] animateTasks:NO];
}

- (void)_selfDidDisappear:(BOOL)animated {
    NSLog(@"此方法用于回调原 ViewController 的 viewDidDisappear 函数指针被替换");
}

@end

#pragma mark - 初始化 Toast 通知
@implementation ToastTask (Initialize)

- (instancetype)initWithView:(UIView *)view {
    self = [super init];
    if (self) {
        _view = view;
    }
    return self;
}

- (instancetype)initWithController:(UIViewController *)controller {
    self = [self initWithView:controller.view];
    if (self) {
        _childController = controller;
    }
    return self;
}

- (BOOL)isEqual:(id)object {
    if (object == nil) {
        return NO;
    } else if (![object isKindOfClass:[self class]]) {
        return NO;
    }
    typeof(self) task = object;
    return self.view == task.view;
}

@end

#pragma mark - 链式更新 Toast 通知 属性
@implementation ToastTask

@synthesize childController = _childController;
@synthesize containerView = _containerView;
@synthesize view = _view;
@synthesize visable = _visable;

/** 将通知视图 添加到 将要显示队列 */
- (instancetype)showOnDismiss:(dispatch_block_t)onDismiss {
    _visable = YES;
    _onDismissBlock = [onDismiss copy];

    CGRect frame = _view.frame;
    if (CGSizeEqualToSize(frame.size, CGSizeZero)) {
        frame.size = [_view sizeThatFits:CGSizeMake(MIN(ScreenSize.width, ScreenSize.height) - 30, CGFLOAT_MAX)];
        _view.frame = frame;
    }
    if (_containerView == nil) {
        _containerView = [ToastManager createContainerView:self];
        _view.center = _containerView.center;
    }
    frame = _containerView.frame;
    if (CGSizeEqualToSize(frame.size, CGSizeZero)) {
        frame = _view.frame;
        UIEdgeInsets insets = _viewInsets;
        CGFloat width = CGRectGetWidth(frame) + insets.left + insets.right;
        CGFloat height = CGRectGetHeight(frame) + insets.top + insets.bottom;
        _containerView.frame = CGRectMake(frame.origin.x - insets.left, frame.origin.y - insets.top, width, height);
        frame.origin = CGPointMake(insets.left, insets.top);
        _view.frame = frame;
//        _autoresizingMask =
//        UIViewAutoresizingFlexibleLeftMargin |
//        UIViewAutoresizingFlexibleRightMargin |
//        UIViewAutoresizingFlexibleTopMargin |
//        UIViewAutoresizingFlexibleBottomMargin;
    }
    
    _defaultSize = _containerView.frame.size;
    _defaultTransform = _containerView.transform;
    _defaultCornerRadius = _containerView.layer.cornerRadius;
    
    [_containerView addSubview:_view];
    
    
    if (!_overlay && _duration > 0) {
        _dismissTime = CACurrentMediaTime() + _duration + (Toast.toastQueue.count > 2 ? Toast.minDismissAfter : 0); // 计算消失时间
    }
    // 根据自动关闭时间判断是加入哪种 队列
    NSMutableArray *queue = _overlay ?
    Toast.modalQueue :
    (_duration > 0 ? Toast.toastQueue : Toast.stateQueue);
    if ([queue indexOfObject:self] == NSNotFound ) {
        [queue addObject:self];
        [Toast animateTasks:NO];
    }
    return self;
}

/** 立即隐藏此 Toast  */
- (void)dismiss {
    [self dismissLater];
    [Toast animateTasks:NO];
}
/** 在下一轮动画中隐藏 Toast  */
- (void)dismissLater {
    _visable = NO;
    
    NSMutableArray *queue = _overlay ?
    Toast.modalQueue :
    (_duration > 0 ? Toast.toastQueue : Toast.stateQueue);
    
    NSInteger index = [queue indexOfObject:self];
    if (index != NSNotFound) {
        [queue removeObjectAtIndex:index];
    }
    
    index = [Toast.cleanQueue indexOfObject:self];
    if (index == NSNotFound && !_overlay && _duration > 0) {
        [Toast.cleanQueue addObject:self];
    }
    
    if (_overlay && [Toast->_currentModal isEqual:self]) {
        [Toast.cleanQueue addObject:self];
        Toast->_currentModal = nil;
    } else if ([Toast->_currentToast isEqual:self]) {
        [Toast.cleanQueue addObject:self];
        Toast->_currentToast = nil;
    }
}

#pragma mark 链式语法补充参数设置
- (TOAST_CTLR)dismissWhenDidDisappear {
    __weak typeof(self) weakSelf = self;
    return ^(UIViewController * controller) {
        [controller registerToastController];
        _parentController = controller;
        return weakSelf;
    };
}

- (TOAST_VIEW)backgroundView {
    __weak typeof(self) weakSelf = self;
    return ^(UIView * view) {
        _containerView = view;
        return weakSelf;
    };
}

- (TOAST_TIME)autoDismissLaterThan {
    __weak typeof(self) weakSelf = self;
    return ^(NSTimeInterval second) {
        _duration = second;
        return weakSelf;
    };
}

- (TOAST_CALL)showAnimations {
    __weak typeof(self) weakSelf = self;
    return ^(dispatch_block_t block) {
        _showAnimationsBlock = [block copy];
        return weakSelf;
    };
}
- (TOAST_CALL)hideAnimations {
    __weak typeof(self) weakSelf = self;
    return ^(dispatch_block_t block) {
        _hideAnimationsBlock = [block copy];
        return weakSelf;
    };
}

- (TOAST_EDGE)layoutInsets {
    __weak typeof(self) weakSelf = self;
    return ^(UIEdgeInsets insets) {
        _viewInsets = insets;
        return weakSelf;
    };
}

- (TOAST_MASK)autoresizingMask {
    __weak typeof(self) weakSelf = self;
    return ^(UIViewAutoresizing mask) {
        _autoresizingMask = mask;
        return weakSelf;
    };
}

- (ToastModal *)hasOverlay {
    _overlay = YES;
    return (ToastModal *)self;
}

@end

#pragma mark - 模态覆盖层 Toast
@implementation ToastModal

- (ToastModal *)dismissWhenOverlayTapped {
    _overlayDismissOnTapped = YES;
    return self;
}

@end

#pragma mark - ✦ 动画管理 ✦
@implementation ToastManager (Animate)

- (UIWindow *)overlayWindow {
    if (_overlayWindow == nil) {
        UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        window.userInteractionEnabled = YES;
        window.windowLevel = UIWindowLevelStatusBar;
        window.transform = CGAffineTransformIdentity;
        window.backgroundColor = [UIColor clearColor];
        window.rootViewController = [OverlayController new];
        
        _overlayWindow = window;
    }
    return _overlayWindow;
}

- (void)animateTasks:(BOOL)isAfter {
    
    NSTimeInterval minTimestamp = 0;                        // 下次动画最小需要的时间
    NSTimeInterval currentTime = CACurrentMediaTime();      // 当前时间戳
    CGSize screenSize = ScreenSize;                         // 屏幕尺寸
    NSMutableArray *animateList = [NSMutableArray array];   // 需动画处理的 task
    
    // 计算需要实际时间而不是 延迟秒数
    //minDismissAfter += currentTime;
    
    CGFloat interval = 8;                                   // Toast 通知的视图间距
#ifdef Toast_Interval
    interval = Toast_Interval;
#endif
        
    // 独立通知型 Toast
    if (_currentToast == nil && Toast.stateQueue.count > 0) {
        ToastTask *task = Toast.stateQueue[0];
        [Toast.stateQueue removeObjectAtIndex:0];
        
        CGSize size = task->_defaultSize;
        CGFloat x = (screenSize.width - size.width) / 2;
        CGFloat y = (screenSize.height - size.height) / 2;
        task->_frame = CGRectMake(x, y, size.width, size.height);
        task->_cornerRadius = task->_defaultCornerRadius;
        
        _currentToast = task;
        // 加入动画列表
        [animateList addObject:task];
    }
    
    // 将定时消失的 Toast 通知取出判断
    NSMutableArray *queue = Toast.toastQueue;
    for (NSInteger i = queue.count - 1; i >= 0; i--) {
        ToastTask *task = queue[i];
        // 其中超时的都加入移除队列

        if (currentTime > task->_dismissTime) {
            [queue removeObjectAtIndex:i];
            [Toast.cleanQueue addObject:task];
        } else if (minTimestamp > task->_dismissTime || minTimestamp == 0) {
            //  否则计算下次动画最小时间
            minTimestamp = task->_dismissTime;
        }
        // 循环后可得出最小的下次动画启动时间 用于延时回调
    }
    
    // 得出下次动画回调间隔
    NSTimeInterval animateDelay = MAX(minTimestamp - currentTime + 0.05, 0.351);
    
    CGFloat startY = screenSize.height * 0.75;
    CGFloat offsetY = 0;
    
    UIWindow *keyWindow = AppShared.keyWindow ?: AppShared.windows.firstObject;
    
    // 更新 需显示的 toast 的 frame
    for (NSInteger i = queue.count - 1; i >= 0; i--) {
        ToastTask *task = queue[i];
        CGSize size = task->_defaultSize;
        
        CGFloat x = (screenSize.width - size.width) / 2;
        CGFloat y = startY - offsetY - size.height;
        offsetY += size.height + interval;
        
        // 计算等待中的视图 位置
        if (i > 2) {
            task->_containerView.layer.cornerRadius = 8;
            task->_cornerRadius = 8;
            CGFloat side = 16;
            x = (screenSize.width - (CGFloat)(queue.count - 3) * (side + interval)) / 2 + (CGFloat)(i - 3) * (side + interval);
            y = startY + interval;
            size = CGSizeMake(side, side);
            offsetY = 0;
            if (isAfter) { task->_dismissTime += animateDelay; }
            // 计算等待圆点 位置
            [task.view setHidden:YES];
        } else {
            task->_cornerRadius = task->_defaultCornerRadius;
            [task.view setHidden:NO];
        }
        task->_frame = CGRectMake(x, y, size.width, size.height);
        // 加入动画列表
        [animateList addObject:task];
    }
    
    // 将模态(有覆盖层的) Toast 超时的自动移除
    if (_currentModal != nil && _currentModal->_duration > 0 && _currentModal->_dismissTime < currentTime) {
        [Toast.cleanQueue addObject:_currentModal];
        _currentModal = nil;
    } else if (_currentModal != nil && _currentModal->_duration > 0) {
        if (minTimestamp == 0) minTimestamp = _currentModal->_dismissTime;
        minTimestamp = MIN(minTimestamp, _currentModal->_dismissTime);
    }
    
    // 将模态(有覆盖层的) 的 Toast 从队列中取出 并 显示
    if (_currentModal == nil && Toast.modalQueue.count > 0) {
        ToastModal *task = Toast.modalQueue[0];
        [Toast.modalQueue removeObjectAtIndex:0];
        
        if (task->_duration > 0) {
            task->_dismissTime = currentTime + task->_duration;
            if (minTimestamp == 0) minTimestamp = task->_dismissTime;
            minTimestamp = MIN(minTimestamp, task->_dismissTime);
        }
        CGSize size = task->_defaultSize;
        if (CGPointEqualToPoint(task->_containerView.frame.origin, CGPointZero)) {
            CGFloat x = (screenSize.width - size.width) / 2;
            CGFloat y = (screenSize.height - size.height) / 2;
            task->_frame = CGRectMake(x, y, size.width, size.height);
        } else {
            CGPoint origin = task->_containerView.frame.origin;
            task->_frame = CGRectMake(origin.x, origin.y, size.width, size.height);
        }
        task->_cornerRadius = task->_defaultCornerRadius;
        _currentModal = task;
        // 加入动画列表
        [animateList addObject:task];
    }
    
    // 将未显示的通知 显示出来
    for (ToastTask *task in animateList) {
        
        __block UIView *view = task->_containerView;
        __block CGRect  frame = task->_frame;
        __block CGFloat alpha = 1.0;
        __block CGFloat cornerRadius = task->_cornerRadius;
        __block CGAffineTransform transform = task->_defaultTransform;
        
        task->_animationsBlock = ^(){
            view.alpha = alpha;
            view.frame = frame;
            view.layer.cornerRadius = cornerRadius;
            view.transform = transform;
        };
        
        // 如果尚未显示则动画出现
        if (task->_containerView.superview == nil) {
            
            if (task->_showAnimationsBlock == nil) {
                task->_showAnimationsBlock = ^(){
                    CGRect rect = frame;
                    rect.origin.y += 30;
                    view.frame = rect;
                    view.alpha = 0.2;
                    //view.center = CGPointMake(view.center.x, view.center.y - 30);
                };
            }
            // 得出视图起始动画位置
            task->_showAnimationsBlock();
            
            //假设有覆盖层
            if (task->_overlay || task->_duration == 0) {
                UIWindow *window = Toast.overlayWindow;
                [window.rootViewController.view addSubview:task->_containerView];
                if (task->_childController) {
                    [window.rootViewController addChildViewController:task->_childController];
                }
                if (task->_overlayDismissOnTapped) {
                    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:task action:@selector(dismiss)];
                    UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:task action:@selector(dismiss)];
                    tap.delegate = (OverlayController *)window.rootViewController;
                    swipe.delegate = tap.delegate;
                    swipe.direction =
                    UISwipeGestureRecognizerDirectionRight  |
                    UISwipeGestureRecognizerDirectionLeft   |
                    UISwipeGestureRecognizerDirectionUp     |
                    UISwipeGestureRecognizerDirectionDown;
                    [window.rootViewController.view addGestureRecognizer:tap];
                    [window.rootViewController.view addGestureRecognizer:swipe];
                }
                UIColor *color = task->_overlay ? [UIColor colorWithWhite:0.2 alpha:0.6] : [UIColor clearColor];
                window.rootViewController.view.backgroundColor = color;
                window.hidden = NO;
//                [window makeKeyAndVisible];
            } else {
                [keyWindow addSubview:task->_containerView];
            }
            
            // 自动布局当前位置
            task->_containerView.autoresizingMask = task->_autoresizingMask;
            
            if (task->_childController && task->_parentController) {
                [task->_parentController addChildViewController:task->_childController];
            }
            
            // layoutSubViews
            
        }
    }
    
    for (ToastTask *task in Toast.cleanQueue) {
        
        if (task->_hideAnimationsBlock == nil) {
            UIView *view = task->_containerView;
            task->_hideAnimationsBlock = ^(){
                CGFloat animOffset = view.center.y < screenSize.height * 0.35 ? 50 : -50;
                view.center = CGPointMake(view.center.x, view.center.y + animOffset);
                view.alpha = 0.0;
            };
        }
        task->_animationsBlock = task->_hideAnimationsBlock;
        [animateList insertObject:task atIndex:0];
    }
    
    [UIView animateWithDuration:0.35 animations:^{
        for (ToastTask *task in animateList) {
            if (task->_animationsBlock) { task->_animationsBlock(); }
            task->_animationsBlock = nil;
        }
        if (_overlayWindow != nil &&
            _currentModal == nil &&
            Toast.modalQueue.count == 0) {
            _overlayWindow.rootViewController.view.backgroundColor = [UIColor clearColor];
        }
    } completion:^(BOOL finished) {
        for (ToastTask *task in Toast.cleanQueue) {
            if (task->_onDismissBlock) { task->_onDismissBlock(); }
            task->_onDismissBlock = nil;
            [task.view removeFromSuperview];
            [task->_containerView removeFromSuperview];
            [task->_childController removeFromParentViewController];
        }
        if (_overlayWindow != nil &&
            _currentModal == nil &&
            _currentToast == nil &&
            Toast.stateQueue.count == 0 &&
            Toast.modalQueue.count == 0) {
            
            _overlayWindow.hidden = YES;
            _overlayWindow.rootViewController.view.gestureRecognizers = nil;
            [_overlayWindow.rootViewController removeFromParentViewController];
            _overlayWindow.rootViewController = nil;
            [_overlayWindow removeFromSuperview];
            _overlayWindow = nil;
        }
        [Toast.cleanQueue removeAllObjects];
    }];
    
    static NSTimeInterval _lastDismissTime;
    static dispatch_block_t _afterBlock;
    // 如果没有延时回调 则计算最小延时回调时间
    // 如果有更早的动画更新 即使有回调也创建一个新的动画回调
    if ((_afterBlock == nil || minTimestamp < _lastDismissTime) && minTimestamp != 0) {
        //__weak typeof(self) weakSelf = self; // 竟然不好使 应该是OC的BUG
        _afterBlock = ^() {
            _afterBlock = nil;
            //[weakSelf animateTasks:YES];
            [[ToastManager shared] animateTasks:YES];
        };
        
        _lastDismissTime = minTimestamp;
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(animateDelay * NSEC_PER_SEC));
        dispatch_after(time, dispatch_get_main_queue(), ^{
            if (_afterBlock) { _afterBlock(); }
        });
    }

}

/// 过滤给Controller 与之相关的所有ToastTask
+ (NSArray *)toastFilterWithController:(__kindof UIViewController *)controller {
    NSMutableArray *array = [NSMutableArray array];
    
    ToastTask *task;
    task = Toast.currentModal;
    if (task != nil && task->_parentController == controller) {
        [array addObject:task];
    }
    task = Toast.currentToast;
    if (task != nil && task->_parentController == controller) {
        [array addObject:task];
    }
    for (task in Toast.modalQueue) {
        if (task->_parentController == controller) {
            [array addObject:task];
        }
    }
    for (task in Toast.stateQueue) {
        if (task->_parentController == controller) {
            [array addObject:task];
        }
    }
    for (task in Toast.toastQueue) {
        if (task->_parentController == controller) {
            [array addObject:task];
        }
    }
    return array;
}

// 给 viewDidDisappear 注入勾子 勾到函数toastDidDisappear上
+ (void)registerViewControllerClass:(Class)cls {
    if (cls == [UIViewController class] || cls == [UIImagePickerController class]) {
        return;
    }
    
    Method toastDidDisappearMethod = class_getInstanceMethod([UIViewController class], @selector(toastDidDisappear:));
    IMP toastDidDisappearIMP = method_getImplementation(toastDidDisappearMethod);
    
    const char *viewDidDisappearTypes = method_getTypeEncoding(class_getInstanceMethod([UIViewController class], @selector(viewDidDisappear:)));

    // 如果对象 没有 override func viewDidDisappear 则创建一个 并跳转到 taskDidDisappear
    if (!class_addMethod(cls, @selector(viewDidDisappear:), toastDidDisappearIMP, viewDidDisappearTypes)) {
        // 条件成功表明 对象已 override viewDidDisappear
        Method toastDidDisappearAndRecallMethod = class_getInstanceMethod(cls, @selector(toastDidDisappearAndReCall:));
        IMP taskDidDisappearAndRecallIMP = method_getImplementation(toastDidDisappearAndRecallMethod);
        
        IMP viewDidDisappearIMP = class_replaceMethod(cls, @selector(viewDidDisappear:), taskDidDisappearAndRecallIMP, viewDidDisappearTypes);
        
        const char *selfDidDisappearTypes = method_getTypeEncoding(class_getInstanceMethod([UIViewController class], @selector(_selfDidDisappear:)));
        // 并且 创建/替换 一个 __selfDidDisappear 函数为原 override func viewDidDisappear 的指针, 用于回调
        if (!class_addMethod(cls, @selector(_selfDidDisappear:), viewDidDisappearIMP, selfDidDisappearTypes)){
            class_replaceMethod(cls, @selector(_selfDidDisappear:), viewDidDisappearIMP, selfDidDisappearTypes);
        }
    }
}

@end

#pragma mark - 便捷构造 Toast 通知
@implementation ToastManager

@synthesize currentModal = _currentModal;
@synthesize currentToast = _currentToast;

- (NSTimeInterval)minDismissAfter {
    NSTimeInterval minTimestamp = 0;
    NSTimeInterval currentTime = CACurrentMediaTime();      // 当前时间戳
    for (ToastTask *task in Toast.toastQueue) {
        if (currentTime > task->_dismissTime) {
        } else if (minTimestamp > task->_dismissTime || minTimestamp == 0) {
            minTimestamp = task->_dismissTime;
        }
    }
    return minTimestamp - currentTime;
}

+ (UIView *)createContainerView:(ToastTask *)task {
    
    CGRect frame = task->_view.frame;

    if (CGSizeEqualToSize(frame.size, CGSizeZero)) {
        frame.size = [task->_view sizeThatFits:CGSizeMake(MIN(ScreenSize.width, ScreenSize.height) - 30, CGFLOAT_MAX)];
        task->_view.frame = frame;
    }
    UIEdgeInsets insets = task->_viewInsets;
    CGFloat width = CGRectGetWidth(frame) + insets.left + insets.right;
    CGFloat height = CGRectGetHeight(frame) + insets.top + insets.bottom;

//* 模糊透明
    UIToolbar *container = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, width, height)];
    container.userInteractionEnabled = NO;
    container.barStyle = UIBarStyleBlack;
    container.translucent = YES;
    
    container.layer.masksToBounds = YES;// .clipsToBounds = YES;
    container.layer.cornerRadius = 7;
    container.layer.borderColor = [UIColor colorWithWhite:0.8 alpha:0.7].CGColor;
    container.layer.borderWidth = 1 / [UIScreen mainScreen].scale;
//*/
    
/*  半透明
    UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
    container.layer.shadowColor = [UIColor darkGrayColor].CGColor;
    container.layer.shadowOpacity = 0.8;
    container.layer.shadowRadius = 3;
    container.layer.shadowOffset = CGSizeMake(2, 2);
    container.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
    container.layer.masksToBounds = YES;// .clipsToBounds = YES;
    container.layer.cornerRadius = 7;
    
    UIToolbar *mask = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, width, height)];
    mask.userInteractionEnabled = NO;
    mask.barStyle = UIBarStyleBlack;
    mask.translucent = YES;
    
    [container addSubview:mask];minDismissAfter
    mask.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

//*/
    return container;
}

+ (UILabel *)createLabelMaxLines:(CGFloat)numberOfLines {
    UILabel *label = [[UILabel alloc] init];
    label.numberOfLines = numberOfLines;
    label.textColor = [UIColor colorWithWhite:1.0 alpha:0.8];
#ifdef Toast_FontSize
    label.font = [UIFont systemFontOfSize:Toast_FontSize];
#else
    label.font = [UIFont systemFontOfSize:16];
#endif
    
    return label;
}

- (TOAST_CTLR)makeController {
    return ^(UIViewController *controller) {
        return [[ToastModal alloc] initWithController:controller];
    };
}
- (TOAST_VIEW)makeView {
    return ^(UIView *view) {
        return [[ToastModal alloc] initWithView:view];
    };
}
- (TOAST_TEXT)makeText {
    return ^(NSString *text) {
        UILabel *label = [ToastManager createLabelMaxLines:3];
        label.text = text;
        return [[ToastModal alloc] initWithView:label]
        .layoutInsets(UIEdgeInsetsMake(6, 10, 6, 10))
        .autoDismissLaterThan(3)
        .autoresizingMask(UIViewAutoresizingFlexibleLeftMargin    |
                          UIViewAutoresizingFlexibleRightMargin   |
                          UIViewAutoresizingFlexibleTopMargin     |
                          UIViewAutoresizingFlexibleBottomMargin);
    };
}
- (TOAST_ATTR)makeAttr {
    return ^(NSAttributedString *attr) {
        UILabel *label = [ToastManager createLabelMaxLines:3];
        label.attributedText = attr;
        return [[ToastModal alloc] initWithView:label]
        .layoutInsets(UIEdgeInsetsMake(6, 10, 6, 10))
        .autoDismissLaterThan(3)
        .autoresizingMask(UIViewAutoresizingFlexibleLeftMargin    |
                          UIViewAutoresizingFlexibleRightMargin   |
                          UIViewAutoresizingFlexibleTopMargin     |
                          UIViewAutoresizingFlexibleBottomMargin);
    };

}

- (TOAST_TEXT)makeLoading {
    return ^(NSString *text) {
        
        UILabel *label = [ToastManager createLabelMaxLines:1];
        label.text = text;
        
        CGSize size = [label sizeThatFits:CGSizeZero];
        CGFloat width = MAX(MIN(MIN(ScreenSize.width, ScreenSize.height) - 30, size.width),size.height);
        CGFloat height = 70;
        
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
        
        label.frame = CGRectMake(0, height - size.height, width, size.height);
        [view addSubview:label];
        label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;

        UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        [view addSubview:activity];
        activity.center = CGPointMake(width / 2, 25);
        activity.autoresizingMask =
        UIViewAutoresizingFlexibleLeftMargin    |
        UIViewAutoresizingFlexibleRightMargin   |
        UIViewAutoresizingFlexibleTopMargin     |
        UIViewAutoresizingFlexibleBottomMargin;
        [activity startAnimating];
        
        return [[ToastModal alloc] initWithView:view]
        .layoutInsets(UIEdgeInsetsMake(6, 10, 6, 10))
        .autoresizingMask(UIViewAutoresizingFlexibleLeftMargin    |
                          UIViewAutoresizingFlexibleRightMargin   |
                          UIViewAutoresizingFlexibleTopMargin     |
                          UIViewAutoresizingFlexibleBottomMargin);
    };
}

@end

#pragma mark - 单例相关

static dispatch_once_t onceToken;
static ToastManager *instance;
@implementation ToastManager (Once)

+ (nonnull instancetype)shared {
    return [[ToastManager alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
        instance->_modalQueue = [NSMutableArray array];
        instance->_stateQueue = [NSMutableArray array];
        instance->_toastQueue = [NSMutableArray array];
        instance->_cleanQueue = [NSMutableArray array];
    });
    return instance;
}

- (instancetype)init {
    dispatch_once(&onceToken, ^{
        instance = [super init];
        instance->_modalQueue = [NSMutableArray array];
        instance->_stateQueue = [NSMutableArray array];
        instance->_toastQueue = [NSMutableArray array];
        instance->_cleanQueue = [NSMutableArray array];
    });
    self = instance;
    return self;
}

- (id)copy {
    return self;
}

- (id)mutableCopy {
    return self;
}

@end
